<?php

declare(strict_types=1);

namespace App\Services;

use App\BO\UserLocationBO;
use App\Entity\AreaEntity;
use App\Entity\ProductRangeEntity;
use App\Internal\Product\Range;
use App\Models\Area;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class LocationService extends Service
{
    // 不要删除
    public function __construct()
    {
    }

    public static function getCitySet(int $userId)
    {
        // $cityID = session()->get('user.loc_city_id');
        $cityID = UserLocationBO::getUserCityId($userId);
        if ($cityID) {
            $areaModel = new Area();

            return $areaModel->getCity($cityID);
        }

        return false;
    }

    public static function setCity($cityID, $userId = 0)
    {
        $areaModel = new Area();
        $area      = $areaModel->getCity($cityID);
        if ($area) {
            // session()->put('user.loc_city_id', $cityID);
            if ($userId) {
                UserLocationBO::setUserCityId($userId, $cityID);
            }

            return true;
        }

        return false;
    }

    public static function hasServiceInArea($productId, $areaCode)
    {
        $where = [
            'product_id' => $productId,
            'area_code'  => $areaCode,
            'area_level' => 2,
        ];

        return (bool) DB::table('product_ranges')->where($where)->first();
    }


    public static function filterNonProductServAddrByDB($productId, $addresses)
    {
        $productCityRanges = DB::table('product_ranges')->where(['product_id' => $productId, 'area_level' => Range::LEVEL_TWO])->get();
        $servCities        = array_column((array) $productCityRanges->toArray(), 'area_code');
        foreach ($addresses as $key => $addr) {
            $enable = false;
            if ($servCities && in_array($addr['cityid'], $servCities)) {
                $enable = true;
            }
            //地址对当前商品是否生效
            $addresses[$key]->enable = $enable;
        }

        return $addresses->values();
    }

    public static function currentCityAddresses(int $cityId, array $cityData)
    {
        foreach ($cityData as $k => $province) {
            if ($province['value'] != $cityId) {
                unset($cityData[$k]);
            }
        }

        return json_encode($cityData);
    }

    public static function getAntCityData($productId = 0, $formated = true, $jsonType = false, $withDistricts = true)
    {
        $cityData  = [];
        $servAreas = self::getCityData($productId);
        if ($servAreas) {
            if ($formated) {
                foreach ($servAreas as $k => $area) {
                    $cityData[$area->a1id]['title'] = $area->a1name;
                    $cityData[$area->a1id]['key']   = $area->a1id;
                    if (!isset($cityData[$area->a1id]['children'])) {
                        $cityData[$area->a1id]['children'] = [];
                    }
                    $cityData[$area->a1id]['children'][$area->a2id]['title'] = $area->a2name;
                    $cityData[$area->a1id]['children'][$area->a2id]['key']   = $area->a2id;
                    if ($withDistricts) {
                        if (!isset($cityData[$area->a1id]['children'][$area->a2id]['children'])) {
                            $cityData[$area->a1id]['children'][$area->a2id]['children'] = [];
                        }
                        $cityData[$area->a1id]['children'][$area->a2id]['children'][] = [
                            'title' => $area->a3name,
                            'key'   => $area->a3id,
                        ];
                    }
                }
            } else {
                foreach ($servAreas as $k => $area) {
//                    $cityData[] = $area->a1id;
                    $cityData[] = $area->a2id;
                    $cityData[] = $area->a3id;
                }
                $cityData = array_unique($cityData);
            }
        }
        $cityData = array_values($cityData);
        if (is_array($cityData) && $formated) {
            foreach ($cityData as $key => $city) {
                if (is_array($city['children'])) {
                    $cityData[$key]['children'] = array_values($city['children']);
                }
            }
        }
        if ($jsonType) {
            $cityData = json_encode($cityData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }

        return $cityData;
    }

    public static function getAntCityDataWithDash($productId = 0, $formated = true, $jsonType = false, $withDistricts = true)
    {
        $cityData  = [];
        $servAreas = self::getCityData($productId, false);
        if ($servAreas) {
            if ($formated) {
                foreach ($servAreas as $k => $area) {
                    $cityData[$area->a1id]['title']   = $area->a1name;
                    $cityData[$area->a1id]['key']     = $area->a1id;
                    $cityData[$area->a1id]['is_open'] = $area->a1open;
                    if (!isset($cityData[$area->a1id]['children'])) {
                        $cityData[$area->a1id]['children'] = [];
                    }
                    $cityData[$area->a1id]['children'][$area->a2id]['title']   = $area->a2name;
                    $cityData[$area->a1id]['children'][$area->a2id]['key']     = $area->a1id . '-' . $area->a2id;
                    $cityData[$area->a1id]['children'][$area->a2id]['is_open'] = $area->a2open;
                    if ($withDistricts) {
                        if (!isset($cityData[$area->a1id]['children'][$area->a2id]['children'])) {
                            $cityData[$area->a1id]['children'][$area->a2id]['children'] = [];
                        }
                        $cityData[$area->a1id]['children'][$area->a2id]['children'][] = [
                            'title'   => $area->a3name,
                            'key'     => $area->a1id . '-' . $area->a2id . '-' . $area->a3id,
                            'is_open' => $area->a3open,
                        ];
                    }
                }
            } else {
                foreach ($servAreas as $k => $area) {
//                    $cityData[] = $area->a1id;
                    $cityData[] = $area->a1id . '-' . $area->a2id;
//                    $cityData[] = $area->a3id;
                }
                $cityData = array_unique($cityData);
            }
        }
        $cityData = array_values($cityData);
        if (is_array($cityData) && $formated) {
            foreach ($cityData as $key => $city) {
                if (is_array($city['children'])) {
                    $cityData[$key]['children'] = array_values($city['children']);
                }
            }
        }
        if ($jsonType) {
            $cityData = json_encode($cityData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }

        return $cityData;
    }

    public static function getCityData($productId = 0, $withOpen = true)
    {
        $areaSql = 'SELECT
  a1.`id` AS a1id, a1.`areaname` AS a1name, a1.`is_open` AS a1open,
  a2.id AS a2id, a2.`areaname` AS a2name, a2.`is_open` AS a2open,
  a3.`id` AS a3id, a3.`areaname` AS a3name, a3.`is_open` AS a3open
FROM
  `area` AS a1
  INNER JOIN `area` AS a2
    ON a1.`id` = a2.`parentid`
  INNER JOIN `area` AS a3
    ON a2.`id` = a3.`parentid`
WHERE 1
    %s
  AND a1.`level` = 1
  AND a2.`level` = 2
  AND a3.`level` = 3';
        if ($withOpen) {
            $areaSql = sprintf($areaSql, ' AND a1.`is_open` = 1 AND a2.`is_open` = 1 AND a3.`is_open` = 1 ');
        } else {
            $areaSql = sprintf($areaSql, '');
        }
        if ($productId) {
            $rangeSql   = 'SELECT pr.`area_code`, pr.`area_parent` FROM `product_ranges` AS pr WHERE pr.`product_id` = %d ';
            $rangeSql   = sprintf($rangeSql, $productId);
            $servRanges = DB::select($rangeSql);
            if ($servRanges) {
                $areaSql .= ' AND ( ';
                $rangeArr = [];
                foreach ($servRanges as $range) {
                    if ($range->area_parent) {
                        $rangeArr[] = ' ( a2.id = ' . $range->area_code . ' AND a1.id = ' . $range->area_parent . ' ) ';
                    }
                }
                $areaSql .= implode('OR', $rangeArr);
                $areaSql .= ' ) ';
            } else {
                return [];
            }
        }

        return DB::select($areaSql);
    }

    public static function getH5CityData($productId = 0, $formated = true, $jsonType = false, $withDistricts = true)
    {
        $cityData  = [];
        $servAreas = self::getCityData($productId);
        if ($servAreas) {
            if ($formated) {
                foreach ($servAreas as $k => $area) {
                    $cityData[$area->a1id]['text']  = $area->a1name;
                    $cityData[$area->a1id]['value'] = $area->a1id;
                    if (!isset($cityData[$area->a1id]['children'])) {
                        $cityData[$area->a1id]['children'] = [];
                    }
                    $cityData[$area->a1id]['children'][$area->a2id]['text']  = $area->a2name;
                    $cityData[$area->a1id]['children'][$area->a2id]['value'] = $area->a2id;
                    if ($withDistricts) {
                        if (!isset($cityData[$area->a1id]['children'][$area->a2id]['children'])) {
                            $cityData[$area->a1id]['children'][$area->a2id]['children'] = [];
                        }
                        $cityData[$area->a1id]['children'][$area->a2id]['children'][] = [
                            'text'  => $area->a3name,
                            'value' => $area->a3id,
                        ];
                    }
                }
            } else {
                foreach ($servAreas as $k => $area) {
                    $cityData[] = $area->a1id;
                    $cityData[] = $area->a2id;
                    $cityData[] = $area->a3id;
                }
                $cityData = array_unique($cityData);
            }
        }
        $cityData = array_values($cityData);
        if ($jsonType) {
            $cityData = json_encode($cityData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }

        return $cityData;
    }

    public static function getAntAreaData($provinceId = 0, $formated = true, $jsonType = false, $withDistricts = true)
    {
        $areaData  = [];
        $servAreas = self::getAreaData($provinceId);
        if ($servAreas) {
            if ($formated) {
                foreach ($servAreas as $k => $area) {
                    $areaData[$area->a1id]['title']   = $area->a1name;
                    $areaData[$area->a1id]['key']     = $area->a1id;
                    $areaData[$area->a1id]['is_open'] = $area->a1_open;
                    if (!isset($areaData[$area->a1id]['children'])) {
                        $areaData[$area->a1id]['children'] = [];
                    }
                    $areaData[$area->a1id]['children'][$area->a2id]['title']   = $area->a2name;
                    $areaData[$area->a1id]['children'][$area->a2id]['key']     = $area->a2id;
                    $areaData[$area->a1id]['children'][$area->a2id]['is_open'] = $area->a2_open;
                    if ($withDistricts) {
                        if (!isset($areaData[$area->a1id]['children'][$area->a2id]['children'])) {
                            $areaData[$area->a1id]['children'][$area->a2id]['children'] = [];
                        }
                        $areaData[$area->a1id]['children'][$area->a2id]['children'][] = [
                            'title' => $area->a3name,
                            'key'   => $area->a3id,
                        ];
                    }
                }
            } else {
                foreach ($servAreas as $k => $area) {
                    $areaData[] = $area->a1id;
                    $areaData[] = $area->a2id;
                    $areaData[] = $area->a3id;
                }
                $areaData = array_unique($areaData);
            }
        }
        $areaData = array_values($areaData);
        if (is_array($areaData) && $formated) {
            foreach ($areaData as $key => $area) {
                if (is_array($area['children'])) {
                    $areaData[$key]['children'] = array_values($area['children']);
                }
            }
        }
        if ($jsonType) {
            $areaData = json_encode($areaData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }

        return $areaData;
    }

    public static function getAreaData($provinceId = 0)
    {
        $areaSql = 'SELECT
  a1.`id` AS a1id, a1.`areaname` AS a1name, a2.id AS a2id, a2.`areaname` AS a2name, a3.`id` AS a3id, a3.`areaname` AS a3name, a1.`is_open` AS a1_open, a2.`is_open` AS a2_open
FROM
  `area` AS a1
  INNER JOIN `area` AS a2
    ON a1.`id` = a2.`parentid`
  INNER JOIN `area` AS a3
    ON a2.`id` = a3.`parentid`
WHERE a1.`level` = 1
  AND a2.`level` = 2
  AND a3.`level` = 3';
        if ($provinceId) {
            $areaSql .= ' AND ( a1.id = ' . $provinceId . ' ) ';
        }

        return DB::select($areaSql);
    }

    /**
     * @param int $cityId
     * @param int $productId
     * @param bool $formated
     * @param bool $jsonType
     * @param bool $withDistricts
     * @return array
     */
    public static function getAntAreaDataByProduct(int $cityId, int $productId, $formated = true, $jsonType = false, $withDistricts = true)
    {
        $areaData  = [];
        $pr = ProductRangeEntity::findCityArea($cityId, $productId, Range::LEVEL_TWO);
        if (empty($pr)) {
            return [];
        }
        $ids = [];
        foreach ($pr as $p) {
            $ids[] = $p->getAreaCode();
        }
        $servAreas = self::getAreaDataByIds($ids);
        if ($servAreas) {
            if ($formated) {
                foreach ($servAreas as $k => $area) {
                    $areaData[$area->a1id]['title']   = $area->a1name;
                    $areaData[$area->a1id]['key']     = $area->a1id;
                    $areaData[$area->a1id]['is_open'] = $area->a1_open;
                    if (!isset($areaData[$area->a1id]['children'])) {
                        $areaData[$area->a1id]['children'] = [];
                    }
                    $areaData[$area->a1id]['children'][$area->a2id]['title']   = $area->a2name;
                    $areaData[$area->a1id]['children'][$area->a2id]['key']     = $area->a2id;
                    $areaData[$area->a1id]['children'][$area->a2id]['is_open'] = $area->a2_open;
                    if ($withDistricts) {
                        if (!isset($areaData[$area->a1id]['children'][$area->a2id]['children'])) {
                            $areaData[$area->a1id]['children'][$area->a2id]['children'] = [];
                        }
                        $areaData[$area->a1id]['children'][$area->a2id]['children'][] = [
                            'title' => $area->a3name,
                            'key'   => $area->a3id,
                        ];
                    }
                }
            } else {
                foreach ($servAreas as $k => $area) {
                    $areaData[] = $area->a1id;
                    $areaData[] = $area->a2id;
                    $areaData[] = $area->a3id;
                }
                $areaData = array_unique($areaData);
            }
        }
        $areaData = array_values($areaData);
        if (is_array($areaData) && $formated) {
            foreach ($areaData as $key => $area) {
                if (is_array($area['children'])) {
                    $areaData[$key]['children'] = array_values($area['children']);
                }
            }
        }
        if ($jsonType) {
            $areaData = json_encode($areaData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }

        return $areaData;
    }

    /**
     * @param array $ids
     * @return array
     */
    public static function getAreaDataByIds(array $ids)
    {
        $areaSql = 'SELECT
  a1.`id` AS a1id, a1.`areaname` AS a1name, a2.id AS a2id, a2.`areaname` AS a2name, a3.`id` AS a3id, a3.`areaname` AS a3name, a1.`is_open` AS a1_open, a2.`is_open` AS a2_open
FROM
  `area` AS a1
  INNER JOIN `area` AS a2
    ON a1.`id` = a2.`parentid`
  INNER JOIN `area` AS a3
    ON a2.`id` = a3.`parentid`
WHERE a1.`level` = 1
  AND a2.`level` = 2
  AND a3.`level` = 3 and a2.id in (' . implode(',', $ids) . ')';
        return DB::select($areaSql);
    }

    public static function getCityDistricts($cityId)
    {
        return DB::table('area')->where(['parentid' => $cityId, 'level' => 2])->get(['id', 'areaname', 'is_open']);
    }

    public static function isRootArea($areaId)
    {
        return DB::table('area')->where(['id' => $areaId, 'level' => 1, 'parentid' => 0])->first();
    }

    public function getAreaByLocation($area)
    {
        //return User::Query()->where('openid', '=', $openID)->first();
        $appId     = '';
        $appSecret = '';

        return $this->getSignPackage($appId, $appSecret);
    }

    //过滤不提供服务的地址 (基于数据库配置)

    public function getSignPackage($appId, $appSecret)
    {
        $timeStamp   = time();
        $jsapiTicket = getJsApiTicket($appId, $appSecret);
        $protocol    = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? 'https://' : 'http://';
        $url         = "{$protocol}{$_SERVER[HTTP_HOST]}{$_SERVER[REQUEST_URI]}";

        $nonceStr = createNonceStr();
        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket={$jsapiTicket}&noncestr={$nonceStr}&timestamp={$timeStamp}&url={$url}";

        $signature = sha1($string);
        // var_dump($signature);die;
        $signPackage = [
            'appId'     => $appId,
            'nonceStr'  => $nonceStr,
            'timestamp' => $timeStamp,
            'url'       => $url,
            'signature' => $signature,
            'rawString' => $string,
        ];

        return $signPackage;
    }

    //除去非某城市的地址

    /**
     * 返回城市名
     *
     * @param string $cityIds 格式 '1，4，5，111'
     *
     * @return string
     */
    public function getCityNamesByIds(string $cityIds)
    {
        if (!$cityIds) {
            return '全国通用';
        }

        $collection = Area::whereIn('id', explode(',', $cityIds))->get();

        return implode(',', array_column($collection->toArray(), 'areaname'));
    }

    /**
     * 通过 areaname 查找单个城市
     *
     * @return AreaEntity/null
     */
    public function getCityByAreaName(string $areaName)
    {
        $model = Area::where('areaname', '=', $areaName)->first();
        if ($model === null) {
            return $model;
        } else {
            return new AreaEntity($model);
        }
    }

    public function createNonceStr($length = 16)
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str   = '';
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, random_int(0, strlen($chars) - 1), 1);
        }

        return $str;
    }

    public function getJsApiTicket($appId, $appSecret)
    {
        $timeStamp = time();
        if (Redis::exist(config('cache.prefix') . 'jsapi_ticket')) {
            $jsapiTicket = Redis::get(config('cache.prefix') . 'jsapi_ticket');
            // jsapi_ticket 应该全局存储与更新，以下代码以写入到文件中做示例
            $data = json_decode($jsapiTicket);
        }
        // var_dump($data->expire_time);die;
        if (!isset($data) || $data->expire_time < $timeStamp) {
            $accessToken = getAccessToken($appId, $appSecret);
            // 如果是企业号用以下 URL 获取 ticket
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
            $url    = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$accessToken}";
            $res    = json_decode(httpGet($url));
            $ticket = $res->ticket;
            if ($ticket) {
                $data->expire_time  = $timeStamp + 7000;
                $data->jsapi_ticket = $ticket;

                Redis::set(config('cache.prefix') . 'jsapi_ticket', json_encode($data));
            }
        } else {
            $ticket = $data->jsapi_ticket;
        }

        return $ticket;
    }

    public function getAccessToken($appId, $appSecret)
    {
        $timeStamp = time();
        // access_token 应该全局存储与更新，以下代码以写入到文件中做示例
        $data = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '\\access_token.json'));
        if ($data->expire_time < $timeStamp) {
            // 如果是企业号用以下URL获取access_token
            // $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
            $url          = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
            $res          = json_decode(httpGet($url));
            $access_token = $res->access_token;
            if ($access_token) {
                $data->expire_time  = $timeStamp + 7000;
                $data->access_token = $access_token;
                $fp                 = fopen($_SERVER['DOCUMENT_ROOT'] . '\\jsapi_ticket.json', 'w');
                fwrite($fp, json_encode($data));
                fclose($fp);
            }
        } else {
            $access_token = $data->access_token;
        }

        return $access_token;
    }

    public function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_URL, $url);
        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }

    /**
     * @param $productId
     *
     * @return string
     */
    public function getProductServiceCity($productId)
    {
        $cityIds = DB::table('product_ranges')
            ->select('product_ranges.*')
            ->leftJoin('area', 'product_ranges.area_code', '=', 'area.id')
            ->where(['product_id' => $productId, 'area_level' => 1, 'is_open' => 1])
            ->get();
        if (!$cityIds) {
            return '';
        }

        $cityNames = [];
        foreach ($cityIds as $value) {
            $cityNames[] = $this->getCityNameById($value->area_code);
        }

        return implode(',', $cityNames);
    }

    public function getProductServiceCityInfo($productId)
    {
        $cityIds = DB::table('product_ranges')->select('product_ranges.*')->leftJoin('area', 'product_ranges.area_code', '=', 'area.id')->where(['product_id' => $productId, 'area_level' => 1, 'is_open' => 1])->get();
        if (!$cityIds) {
            return '';
        }

        $cityNames = [];
        foreach ($cityIds as $key => $value) {
            $cityNames[$key]['cityId']   = $value->area_code;
            $cityNames[$key]['cityName'] = $this->getCityNameById($value->area_code);
        }

        return $cityNames;
    }

    /**
     * 通过 cityId 查找城市名称
     *
     * @return string
     */
    public function getCityNameById(int $cityId)
    {
        $areaEntity = $this->getCityById($cityId);

        return $areaEntity ? $areaEntity->getAreaname() : '';
    }

    /**
     * 通过 cityId 查找单个城市
     *
     * @return AreaEntity/null
     */
    public function getCityById(int $cityId)
    {
        return AreaEntity::find($cityId);
    }
}
